 
namespace nwWCF
{
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;

    /// <summary>
    /// Cyclic References Aware Contract Behavior
    /// </summary>
    public class CyclicReferencesAwareContract : IContractBehavior
    {
        #region Private Fields

        /// <summary>
        /// 
        /// </summary>
        private const int MaxItemsInObjectGraph = 0xFFFF;

        /// <summary>
        /// 
        /// </summary>
        private const bool IgnoreExtensionDataObject = false;

        /// <summary>
        /// 
        /// </summary>
        private bool on;

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="CyclicReferencesAware"/> class.
        /// </summary>
        /// <param name="on">if set to <c>true</c> [on].</param>
        public CyclicReferencesAwareContract(bool on)
        {
            this.on = on;
        }

        #region IContractBehavior Members

        /// <summary>
        /// Configures any binding elements to support the contract behavior.
        /// </summary>
        /// <param name="contractDescription">The contract description to modify.</param>
        /// <param name="endpoint">The endpoint to modify.</param>
        /// <param name="bindingParameters">The objects that binding elements require to support the behavior.</param>
        public void AddBindingParameters(
            ContractDescription contractDescription,
            ServiceEndpoint endpoint,
            BindingParameterCollection bindingParameters)
        {
        }

        /// <summary>
        /// Applies the client behavior.
        /// </summary>
        /// <param name="contractDescription">The contract description.</param>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="clientRuntime">The client runtime.</param>
        public void ApplyClientBehavior(
            ContractDescription contractDescription,
            ServiceEndpoint endpoint,
            ClientRuntime clientRuntime)
        {
            ReplaceDataContractSerializerOperationBehaviors(contractDescription, this.on);
        }

        /// <summary>
        /// Implements a modification or extension of the client across a contract.
        /// </summary>
        /// <param name="contractDescription">The contract description to be modified.</param>
        /// <param name="endpoint">The endpoint that exposes the contract.</param>
        /// <param name="dispatchRuntime">The dispatch runtime that controls service execution.</param>
        public void ApplyDispatchBehavior(
            ContractDescription contractDescription, 
            ServiceEndpoint endpoint, 
            DispatchRuntime dispatchRuntime)
        {
            ReplaceDataContractSerializerOperationBehaviors(contractDescription, this.on);
        }

        /// <summary>
        /// Implement to confirm that the contract and endpoint can support the contract behavior.
        /// </summary>
        /// <param name="contractDescription">The contract to validate.</param>
        /// <param name="endpoint">The endpoint to validate.</param>
        public void Validate(
            ContractDescription contractDescription,
            ServiceEndpoint endpoint)
        {
        }

        /// <summary>
        /// Replaces the data contract serializer operation behaviors.
        /// </summary>
        /// <param name="contractDescription">The contract description.</param>
        /// <param name="on">if set to <c>true</c> [on].</param>
        internal static void ReplaceDataContractSerializerOperationBehaviors(
            ContractDescription contractDescription, 
            bool on)
        {
            foreach (var operation in contractDescription.Operations)
            {
                ReplaceDataContractSerializerOperationBehavior(operation, on);
            }
        }

        /// <summary>
        /// Replaces the data contract serializer operation behavior.
        /// </summary>
        /// <param name="operation">The operation.</param>
        /// <param name="on">if set to <c>true</c> [on].</param>
        internal static void ReplaceDataContractSerializerOperationBehavior(
            OperationDescription operation, 
            bool on)
        {
            if (operation.Behaviors.Remove(typeof(DataContractSerializerOperationBehavior)) 
                || operation.Behaviors.Remove(typeof(CyclicDataContractSerializer)))
            {
                operation.Behaviors.Add(new CyclicDataContractSerializer(
                    operation, 
                    MaxItemsInObjectGraph, 
                    IgnoreExtensionDataObject, 
                    on));
            }
        }

        #endregion
    }
}
